﻿using System;
using System.IO;
using System.Net;

namespace InDepth2Demo.Chapter10
{
    /// <summary>
    /// 扩展方法的语法
    /// </summary>
    internal class ExtensionMethod
    {
        // 用扩展方法复制一个流 
        public static void Call()
        {
            WebRequest request = WebRequest.Create("http://manning.com");

            using (WebResponse response = request.GetResponse())
            using (Stream responseStream = response.GetResponseStream())
            using (FileStream output = File.Create("response.dat"))
            {
                responseStream.CopyTo1(output);
            }
        }


        public static void Call2()
        {
            object y = null;
            Console.WriteLine(y.IsNull());          // True
            //Console.WriteLine(y.GetHashCode());     // System.NullReferenceException:“ 未将对象引用设置到对象的实例。”
            y = new object();
            Console.WriteLine(y.IsNull());          // False 
        }
    }

    //包含扩展方法的 StreamUtil类
    public static class StreamUtil
    {
        const int BufferSize = 8192;

        public static void CopyTo1(this Stream input, Stream output)
        {
            byte[] buffer = new byte[BufferSize];
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, read);
            }
        }

        public static byte[] ReadFully(this Stream input)
        {
            using (MemoryStream tempStream = new MemoryStream())
            {
                input.CopyTo1(tempStream);
                return tempStream.ToArray();
            }
        }
    }

    // 在空引用上调用扩展方法
    public static class NullUtil
    {
        public static bool IsNull(this object x)       //在这段代码中，扩展的定义方式是不规范的。代码扩展了object类型，所有继承于object的类型都将具有该扩展方法，这就对其他子类型产生了“污染”。之所以叫它污染，是因为我们定义的扩展方法本来只想扩展某个子类（如前面的代码只想扩展string类型），却意外地造成了原本不想造成的后果。
        {
            return x == null;
        }

        public static bool isNull(this string str)      //所以当我们为一个类型定义扩展方法时，应尽量扩展具体的类型，而不要扩展其基类。
        {
            return str == null;
        }
    }

}
